
class Vector:
    rely = "Allocator Ut"
    std = "ds_base"
    def __init__(self):
        self.start = "char*"
        self.end = "char*"
        self.margin = "char*"
        self.element_size = "int"
    
    @staticmethod
    def demo_keep():# void|>
        __data(Vector, v1)
        __data(Vector, v2)
        
        __keep_source( v1.init(sizeof(int)) )
        if 1:
            v2.init(sizeof(int))
        
        __data(Vector, v3)
        v3.init(sizeof(int))
        while 1:
            __data(Vector, v4)
            v4.init(sizeof(int))    
            if 1:
                break
            if 2:
                return 
            if 3: 
                raise

    @staticmethod
    def unit_test():# void|>
        __data(Vector, arr)
        __data(Vector, arr1)
        arr.init(sizeof(int))
        arr1.init(sizeof(int))
        int| i
        int| j
        int*| i_iter
        int*| j_iter
        for i in range(0, 5):
            arr.push(&i)
            i_iter = arr.at(i)
            UtEq(Ut_Int, "", *i_iter, i)

            int*| i_iter
            for j, j_iter in enumerate(arr1):
                i_iter = arr.at(j)
                UtEq(Ut_Int, "", *i_iter, *j_iter)
            arr1.push(&i)
            
        for i in range(0, 5):
            arr1.pop()
            for j, j_iter in enumerate(arr1):
                i_iter = arr.at(j)
                UtEq(Ut_Int, "", *i_iter, *j_iter)
            arr.pop()

    @__source(deinit)
    def init(self, e_size): # void |>int>
        self.clear()
        if e_size < 0:
            raise "e_size < 0"
        Memory.bzero(self, sizeof(Vector_obj))
        if e_size != 0:
            self.set_e_size(e_size)
            self.ensure_memory_enough(1)
    def deinit(self): # void |> 
        self.clear()
    
    def e_size(self): # int |>
        return self.element_size
    def capacity(self): # int |>
        if self.e_size() != 0:
            int| byte = self.margin - self.start
            return byte/self.e_size()
        return 0
        
    def size(self): # int |>
        if self.e_size() != 0:
            int| byte = self.end - self.start
            return byte/self.e_size()
        return 0
    def set_e_size(self, new_e_size): # void |>int>
        self.element_size = new_e_size
    def set_capacity(self, capa):# void |>int>
        self.margin = self.start + self.e_size()* capa
        if capa < self.size():
            self.set_size(capa)
    def set_size(self, sz):# void |> int>
        self.end = self.start + self.e_size()* sz
    def need_memory(self, e_num):# int|>int>
        return e_num* self.e_size()
    def ensure_memory_enough(self, e_number):#void |> int>
        int| old_size = self.size()
        if self.capacity() < e_number:
            int| old_capacity = self.capacity()
            int| new_capacity = Allocator.capacity_double_calc(self.capacity(), e_number)
            __data(Allocator, alloc)
            alloc.alloc(self.need_memory(new_capacity))
            if old_size > 0:
                alloc.linear_copy(self.start, self.need_memory(self.size()), 0)
            self.start = alloc.get_memory(self.start)
            self.set_size(old_size)
            self.set_capacity(new_capacity)
    def clear(self):# void |> 
        Memory_free(self.start)
        self.end = self.start
        self.margin = self.start

    def reverse(self):# void |> 
        int| n = self.size()
        int| i
        for i in range(0, n):
            if i >= n-1-i:
                break
            self.swap(i, n-1-i)

        
    def swap(self, i1, i2): # void |> int > int>
        char*| d1 = self.at(i1)
        char*| d2 = self.at(i2)
        Memory.swap(d1, d2, self.e_size())

    def pop_i(self, i): # void* |> int> 
        self.swap(i, self.size() - 1)
        return self.pop()

    def push(self, e):# void |> void*>
        if self.e_size() == 0: 
            return
        if e == NULL:
            raise "element is NULL"
        if self.start == NULL:
            raise "array not init!"
        self.ensure_memory_enough(self.size()+1)
        self.push_uncheck(e)
    
    def push_custom(self, e, copy_proc):# void |> void*> void*(void*)>
        self.ensure_memory_enough(self.size()+1)
        self.push_uncheck(e)

    def pop(self): # void* |> 
        if self.size() > 0:
            self.end -= self.e_size()
        return self.end


    def push_uncheck(self, e): # void |> void*> 
        if self.capacity() <= self.size():
            raise "capacity not enough!"
        if self.e_size() == 0:
            raise "e_size = 0"
        if e == NULL:
            raise "element pointer is NULL"
        Memory.copy(self.end, e, self.e_size())
        self.end += self.e_size()
    def at(self, n): # void* |> int>
        return Memory.safe_at(self.start, self.e_size(), n, self.size() )

    def delete(self, e): # void |> void*>
        int| pos = self.find(e)
        if pos != DS_SIZE_NIL:
            self.pop_i(pos)

    def find(self, e): # int |> void*> 
        int| i
        void*| cur_e
        for i, cur_e in enumerate(self):
            if Memory.same(cur_e, e, self.e_size()):
                return i
        return DS_SIZE_NIL
    def same(self, that):# ds_bool |> Vector_obj*>
        if self.size() == that.size() and self.e_size() == that.e_size():
            return Memory.same(self.start, that.start, self.size()*self.e_size())
        return 0
    def merge(self, ext): # void |> Vector_obj*>  
        if self.e_size() != ext.e_size():
            raise "merge fail! e_size is different"
        void*| e
        for e in ext:
            self.push(e)
    def Begin(self): # void* |>
        return self.start
    def not_End(self, Iter): # int |> void*>
        if `char*|Iter` < `char*|self.end`:
            return 1
        return 0
    def Next(self, iter):# void*|> void*>
        char*| p = iter
        return &p[self.element_size]

